package com.bootdo.clouddo.task;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bootdo.clouddo.config.TaskConfig;
import com.bootdo.clouddo.domain.douban.*;
import com.bootdo.clouddo.service.douban.*;
import com.bootdo.clouddo.utils.douban.DbBookUtil;
import com.bootdo.clouddo.utils.StringUtils;
import com.bootdo.clouddo.utils.http.DoubanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.*;

//@RunWith(SpringRunner.class)
//@SpringBootTest(classes={ClouddoCmsApplication.class}, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)// 指定启动类
@Component
public class DoubanTask {

    @Autowired
    private IDbBookTagService tagService;

    @Autowired
    private IDbBookDetailService detailService;

    @Autowired
    private IDbBookInterestService interestService;

    @Autowired
    private IDbUserService userService;

    @Autowired
    private IDbBookReviewService reviewService;
    @Autowired
    private IDbBookReviewFullService reviewFullService;
    @Autowired
    private IDbBookRatingService ratingService;
    @Autowired
    private IDbSubjectCollectionService collectionService;
    @Autowired
    private IDbSubjectCollectionItemService collectionItemService;

    @Autowired
    private IDbBookRecommendationService recommendationService;

    //@Async("myExecutor")
    //@Scheduled(fixedRate = 60000*60*24*66)
    public void test(){
        //getAnnotation(34262174L);
        //List<Long> ids = ratingService.findNoRatingIds();
        //Collections.shuffle(ids);
    }

    /**
     * 添加短评和书评
     */
    //@Async("myExecutor")
    //@Scheduled(fixedRate = 60000*60)
    //@Scheduled(cron="0 0/30 * * * ? ")
    public void getOthers(){
        if(!TaskConfig.doubanTaskRun)
            return;
        List<Long> ids = interestService.findNoInterestIds();
        Collections.shuffle(ids);
        ids.stream().forEach(id->{
            try {
                Thread.sleep(Long.valueOf(StringUtils.getRandom(2)));
                getInterests(id);
                getReview(id);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 添加推荐
     */
    //@Async("myExecutor")
    //@Scheduled(fixedRate = 60000*60)
    public void getRec(){
        List<Long> ids = collectionItemService.findAllIds();
        //List<Long> ids = detailService.getAllIds();
        Collections.shuffle(ids);
        ids.stream().forEach(id->{
            try {
                Thread.sleep(Long.valueOf(StringUtils.getRandom(3)));
                getRecommend(id);
            } catch (Exception e) {
                e.printStackTrace();
            }
        });
    }

    /**
     * 查询列表中的book
     */
    //@Async("myExecutor")
    //@Scheduled(fixedRate = 60000*60)
    public void getCollectionSubjects(){
        List<Long> ids = collectionItemService.findAllIds();
        Collections.shuffle(ids);
        ids.stream().forEach(id ->{
            try{
                getDetail(id, true);
            }catch (Exception e){e.printStackTrace();}
        });
    }

    /**
     * 查询有评分的书籍
     */
    //@Async("myExecutor")
    //@Scheduled(fixedRate = 60000*60*24*66)
    public void getDetail1(){
        for (long i = 2506107; i < 2601034; i++) {
            try{
                getDetail(i, false);
            }catch (Exception e){e.printStackTrace();}
        }
    }

    /**
     * 倒序查询有评分的书籍
     */
    //@Async("myExecutor")
    //@Scheduled(fixedRate = 60000*60*24*66)
    public void getDetail2(){
        for (long i = 2601034; i > 2506107; i--) {
            try{
                getDetail(i, false);
            }catch (Exception e){e.printStackTrace();}
        }
    }

//    @Async("myExecutor")
//    @Scheduled(fixedRate = 60000*60*24*66)
    public void getOther1(){
        for (long i = 1073253; i < 2000000; i++) {
            try{
                Thread.sleep(Long.valueOf(StringUtils.getRandom(3)));
                getInterests(i);
                getReview(i);
            }catch (Exception e){e.printStackTrace();}
        }
    }

    //@Async("myExecutor")
    //@Scheduled(cron="0 30 8 0/7 * ? ")
    public void getAllCollection(){
        getItem();
    }


    private void saveTag(DbBookDetail post) {
        try {
            JSONArray ja = JSONArray.parseArray(post.getTags());
            for (Object obj : ja) {
                JSONObject jo = (JSONObject)obj;
                DbBookTag tag = jo.toJavaObject(DbBookTag.class);
                if(tagService.get(tag.getId()) == null) {
                    tagService.save(tag);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }



    //@Async("myExecutor")
    //@Scheduled(fixedRate = 60000*60*24*66)
    public void timelineSocket() {
        getItem();
    }

    public void getDetail(Long id, boolean force){
        if(!force && detailService.findById(id) != null)
            return;

        Map<String, String> params = new LinkedHashMap<>();
        // 详情
        String url = "https://m.douban.com/rexxar/api/v2/book/" + id+ "?ck=&for_mobile=1";

        //讨论
        //String url = "https://m.douban.com/rexxar/api/v2/book/34262174/forum_topics?start=0&count=5&ck=&for_mobile=1";
        //String url_market = "https://m.douban.com/rexxar/api/v2/market/book/34262174?appVersion=4.18&ck=&for_mobile=1";

        url = url + "?" + DoubanUtils.parseParams(params);
        //发送Post数据并返回数据
        try{
            Thread.sleep(Long.valueOf(StringUtils.getRandom(2)));
            String data = DoubanUtils.downloadPage(url, true);
            data = data.replaceAll("00b7", "·").replaceAll("30fb", "・").replaceAll("00b0", "°");
            //System.out.println(JSON.toJSONString(data));
            if(StringUtils.isEmpty(data))
                return;
            JSONObject jo = JSON.parseObject(data);
            if(jo == null || StringUtils.equals(jo.getString("code"), "404"))
                return;
            String msg = jo.getString("msg");
            if(StringUtils.isNoneEmpty(msg) && msg.contains("rate_limit")) {
                System.out.println("被限速了，再等等吧。。。。");
                Thread.sleep(1000 * 60 * 15);
            }
            //System.out.println("发现一条数据：" + JSON.toJSONString(data));
            DbBookDetail detail = jo.toJavaObject(DbBookDetail.class);
            if(StringUtils.isNoneEmpty(detail.getRating()))
                detail.setRatingValue(JSON.parseObject(detail.getRating()).getDouble("value"));
            System.out.print("成功转换一条数据：" + detail.getId() + "==>" + detail.getTitle());
//            if(!force && (detail.getRatingValue() == null || detail.getRatingValue() <= 0)) {
//                System.out.println("--没评分，不要了");
//                return;
//            } else{
//                System.out.println("--评分:" + detail.getRatingValue());
//            }
            detailService.saveOrUpdate(detail);
            // 保存标签
            saveTag(detail);
            // 保存简评
            getInterests(detail.getId());
            // 保存书评
            getReview(detail.getId());
            // 保存评分
            getRating(detail.getId());
            // 保存猜你喜欢
            //getRecommend(detail.getId());
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void getRating(Long id){

        Map<String, String> params = new LinkedHashMap<>();
        // 详情
        String url = "https://m.douban.com/rexxar/api/v2/book/" + id + "/rating?ck=&for_mobile=1";

        url = url + "?" + DoubanUtils.parseParams(params);
        //发送Post数据并返回数据
        try{
            Thread.sleep(Long.valueOf(StringUtils.getRandom(3)));
            String data = DoubanUtils.downloadPage(url, true);
            if(StringUtils.isEmpty(data))
                return;
            JSONObject jo = JSON.parseObject(data);
            if(jo == null || StringUtils.equals(jo.getString("code"), "404"))
                return;
            String msg = jo.getString("msg");
            if(StringUtils.isNoneEmpty(msg) && msg.contains("rate_limit")) {
                System.out.println("被限速了，再等等吧。。。。");
                Thread.sleep(1000 * 60 * 15);
            }
            //System.out.println("发现一条数据：" + JSON.toJSONString(data));
            DbBookRating detail = jo.toJavaObject(DbBookRating.class);
            detail.setId(id);
            detail.setUpdateTime(new Date());

            if(ratingService.findById(id) == null)
                System.out.print("成功转换一条评分：" + detail.getId());

            ratingService.save(detail);
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

    public void getRecommend(Long id){
        String url = "https://frodo.douban.com/api/v2/book/" + id + "/recommendations?apiKey=054022eaeae0b00e0fc068c0c0a2102a";
        //发送Post数据并返回数据
        try{
            String data = DoubanUtils.getStrRequest(url, new HashMap<>());
            System.out.println(JSON.toJSONString(data));
            data = data.replaceAll("00b7", "·").replaceAll("30fb", "・").replaceAll("00b0", "°");
            //System.out.println(JSON.toJSONString(data));
            if(StringUtils.isEmpty(data))
                return;
            if(StringUtils.isNotEmpty(data) && data.contains("rate_limit"))
                Thread.sleep(1000 * 60 * 15);
            //System.out.println("发现一条数据：" + JSON.toJSONString(data));
            List<DbBookRecommendation> list = JSON.parseArray(data, DbBookRecommendation.class);
            if(list == null || list.size() == 0)
                return;
            list.stream().forEach(dd ->{

                if(StringUtils.isNoneEmpty(dd.getRating()))
                    dd.setRatingValue(JSON.parseObject(dd.getRating()).getDouble("value"));

                // 保存用户
                dd.setSid(dd.getId().longValue());
                dd.setId(null);
                dd.setSubjectId(id);
                dd.setAddTime(new Date());

                // 获取关联的图书
                getDetail(dd.getSid(), true);

                if(recommendationService.exists(dd.getId(), id))
                    return;
                // 保存
                System.out.println("[" + id + "]成功转换一条推荐：" + dd.getId() + "==>" + dd.getTitle());
                recommendationService.save(dd);

            });
        }catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void getAnnotation(Long id){
        Map<String, String> params = new LinkedHashMap<>();
        int start = 0;
        while(true) {
            String url = "https://m.douban.com/rexxar/api/v2/book/" + id + "/annotations?count=50&order_by=hot&start="+start+"&ck=&for_mobile=1";
            start += 50;
            url = url + "?" + DoubanUtils.parseParams(params);
            //发送Post数据并返回数据
            try{
                String data = DoubanUtils.downloadPage(url, true);
                System.out.println(JSON.toJSONString(data));
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void getInterests(Long id){
        Map<String, String> params = new LinkedHashMap<>();
        int start = 0;
        while(true) {
            if(start > 300)
                return;
            String url = "https://m.douban.com/rexxar/api/v2/book/" + id + "/interests?count=50&order_by=hot&start="+start+"&ck=&for_mobile=1";
            start += 50;
            // 书评
            //String url = "https://m.douban.com/rexxar/api/v2/book/34262174/reviews?count=50&order_by=hot&start=0&ck=&for_mobile=1";

            //讨论
            //String url = "https://m.douban.com/rexxar/api/v2/book/34262174/forum_topics?start=0&count=5&ck=&for_mobile=1";
            //String url_market = "https://m.douban.com/rexxar/api/v2/market/book/34262174?appVersion=4.18&ck=&for_mobile=1";

            url = url + "?" + DoubanUtils.parseParams(params);
            //发送Post数据并返回数据
            try{
                String data = DoubanUtils.downloadPage(url, true);
                data = data.replaceAll("00b7", "·").replaceAll("30fb", "・").replaceAll("00b0", "°");
                //System.out.println(JSON.toJSONString(data));
                if(StringUtils.isEmpty(data))
                    return;
                JSONObject jo = JSON.parseObject(data);
                if(jo == null)
                    return;
                String msg = jo.getString("msg");
                if(StringUtils.isNoneEmpty(msg) && msg.contains("rate_limit"))
                    Thread.sleep(1000 * 60 * 15);
                //System.out.println("发现一条数据：" + JSON.toJSONString(data));
                JSONArray ja = jo.getJSONArray("interests");
                if(StringUtils.equals(jo.getString("code"), "404") || ja == null || ja.size() == 0)
                    return;
                ja.stream().forEach(dd ->{
                    DbBookInterest interest = ((JSONObject)dd).toJavaObject(DbBookInterest.class);
                    if(interestService.findById(interest.getId()) != null)
                        return;
                    if(StringUtils.isNoneEmpty(interest.getRating()))
                        interest.setRatingValue(JSON.parseObject(interest.getRating()).getDouble("value"));
                    if(interest.getRatingValue() == null || interest.getRatingValue() < 4)
                        return;
                    if(interestService.findById(interest.getId()) == null)
                        System.out.println("[" + id + "]成功转换一条简评：" + interest.getId() + "==>" + interest.getComment());
                    // 保存用户
                    interest.setUserId(getUser(((JSONObject)dd).getJSONObject("user")).getId());
                    interest.setSubjectId(id);
                    // 保存短评
                    interestService.save(interest);
                });
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void getReview(Long id){
        Map<String, String> params = new LinkedHashMap<>();
        int start = 0;
        while(true) {
            String url = "https://m.douban.com/rexxar/api/v2/book/" + id + "/reviews?count=50&order_by=hot&start=" + start + "&ck=&for_mobile=1";
            start += 50;

            //讨论
            //String url = "https://m.douban.com/rexxar/api/v2/book/34262174/forum_topics?start=0&count=5&ck=&for_mobile=1";
            //String url_market = "https://m.douban.com/rexxar/api/v2/market/book/34262174?appVersion=4.18&ck=&for_mobile=1";

            url = url + "?" + DoubanUtils.parseParams(params);
            //发送Post数据并返回数据
            try{
                String data = DoubanUtils.downloadPage(url, true);
                data = data.replaceAll("00b7", "·").replaceAll("30fb", "・").replaceAll("00b0", "°");
                //System.out.println(JSON.toJSONString(data));
                if(StringUtils.isEmpty(data))
                    return;
                JSONObject jo = JSON.parseObject(data);
                if(jo == null)
                    return;
                String msg = jo.getString("msg");
                if(StringUtils.isNoneEmpty(msg) && msg.contains("rate_limit"))
                    Thread.sleep(1000 * 60 * 15);
                //System.out.println("发现一条数据：" + JSON.toJSONString(data));
                JSONArray ja = jo.getJSONArray("reviews");
                if(StringUtils.equals(jo.getString("code"), "404") || ja == null || ja.size() == 0)
                    return;
                ja.stream().forEach(dd ->{
                    DbBookReview record = ((JSONObject)dd).toJavaObject(DbBookReview.class);

                    if(StringUtils.isNoneEmpty(record.getRating()))
                        record.setRatingValue(JSON.parseObject(record.getRating()).getDouble("value"));
                    record.setAbstr(((JSONObject)dd).getString("abstract"));
                    if(reviewService.findById(record.getId()) == null)
                        System.out.println("[" + id + "]成功转换一条书评：" + record.getId() + "==>" + record.getTitle());
                    // 获取用户
                    record.setUserId(getUser(((JSONObject)dd).getJSONObject("user")).getId());
                    record.setSubjectId(id);
                    // 保存评论
                    reviewService.save(record);
                    // 获取评论详情
                    getReviewDetail(record.getId(), id);
                });
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    public void getReviewDetail(Long id, Long subjectId){
        Map<String, String> params = new LinkedHashMap<>();
        String url = "https://book.douban.com/j/review/" + id + "/full";

        //发送Post数据并返回数据
        try{
            JSONObject data = DoubanUtils.getRequest(url);
            //System.out.println(JSON.toJSONString(data));
            if(data == null)
                return;
            DbBookReviewFull full = new DbBookReviewFull();
            full.setHtml(data.getString("html"));
            full.setVotes(data.getString("votes"));
            full.setVoteScript(data.getString("vote_script"));
            JSONObject votes = data.getJSONObject("votes");
            if(votes != null)
                full.setUsefulCount(votes.getInteger("useful_count"));
            else
                full.setUsefulCount(0);
            full.setId(id);
            full.setSubjectId(subjectId);
            reviewFullService.save(full);
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

    public DbUser getUser(JSONObject ju){
        if(ju != null) {
            if(userService.findById(ju.getLong("id")) == null) {
                DbUser user = ju.toJavaObject(DbUser.class);
                userService.save(user);
                return user;
            }
        }
        return new DbUser(ju.getLong("id"));
    }


    private String[] collections = {
            "https://m.douban.com/rexxar/api/v2/subject_collection/book_top250/items",
            "https://m.douban.com/rexxar/api/v2/subject_collection/book_latest/items",
            "https://m.douban.com/rexxar/api/v2/subject_collection/book_score/items",
            "https://m.douban.com/rexxar/api/v2/subject_collection/book_hot/items",
            "https://m.douban.com/rexxar/api/v2/subject_collection/book_classic/items",
            "https://m.douban.com/rexxar/api/v2/subject_collection/book_film_original/items",
            "https://m.douban.com/rexxar/api/v2/subject_collection/book_fiction/items",
            "https://m.douban.com/rexxar/api/v2/subject_collection/book_nonfiction/items"};



    public void getItem(){
        Map<String, String> params = new LinkedHashMap<>();
        params.put("os", "ios");
        params.put("for_mobile", "1");
        params.put("count", "50");
        params.put("loc_id", "0");

        A: for(String url: collections) {
            int start = 0;
            int sort = 1;
            url = url + "?" + DoubanUtils.parseParams(params);
            List<DbSubjectCollectionItem> items = new ArrayList<>();
            DbSubjectCollection collection = null;
            while(true) {
                String cuurl = url + "&start=" + start;
                start += 50;
                //发送Post数据并返回数据
                try{
                    String data = DoubanUtils.downloadPage(cuurl, true);
                    System.out.println(JSON.toJSONString(data));
                    data = data.replaceAll("00b7", "·").replaceAll("30fb", "・").replaceAll("00b0", "°");
                    JSONObject jo = JSON.parseObject(data);
                    JSONObject sug = jo.getJSONObject("subject_collection");
                    if(sug == null)
                        continue;
                    JSONArray ja = jo.getJSONArray("subject_collection_items");
                    if(ja.size() == 0)
                        break;
                    if(collection == null)
                        collection = JSON.toJavaObject(sug, DbSubjectCollection.class);
                    for (int i = 0; i < ja.size(); i++) {
                        DbSubjectCollectionItem item = JSON.toJavaObject(ja.getJSONObject(i), DbSubjectCollectionItem.class);
                        item.setSubjectId(ja.getJSONObject(i).getLong("id"));
                        item.setId(null);
                        item.setCollectionId(collection.getId());
                        item.setSort(sort);
                        sort ++;
                        if(StringUtils.isNoneEmpty(item.getRating()))
                            item.setRatingValue(JSON.parseObject(item.getRating()).getDouble("value"));
                        System.out.println("["+ collection.getId() +"]"+sort+"成功转换一条数据：==>" + item.getTitle());
                        items.add(item);
                    }
                }catch (Exception e) {
                    e.printStackTrace();
                    // 一旦出异常，直接跳出当前循环
                    continue A;
                }
            }
            if(collection != null && items.size() > 10) {
                collectionService.save(collection);
                collectionItemService.saveBatch(items);
                items.stream().forEach(it->{getDetail(it.getSubjectId(), false);});
            }
        }

    }

    //@Test
    public void getTags(){
        Map<String, String> params = new LinkedHashMap<>();
        params.put("_need_webp", "0");
        params.put("_sig", "6wnUmM%2B%2BeEl/NK3kRCzrDh5DzqI%3D");
        //params.put("_ts", "1572790171");
        params.put("apikey", "0ab215a8b1977939201640fa14c66bab");
        params.put("douban_udid", "17ce66b5b7d85c4cd380c4a38982465423a825a8");
        params.put("dumpling", "290CD640-851D-42FE-9616-0E9100873B0E");
        params.put("loc_id", "108288");
        params.put("sugar", "46001");
        params.put("udid", "b0b995fef0fb1aa0f96defe45393202f96056959");
        params.put("watermelon", "9EDAAEFA-CA6F-49E5-BA4B-99EBE481BB4D");

        String url = "https://frodo.douban.com/api/v2/book/landing";
        url = url + "?" + DoubanUtils.parseParams(params);
        //发送Post数据并返回数据
        try{
            String data = DoubanUtils.downloadPage(url, false);
            System.out.println(JSON.toJSONString(data));
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

    //@Test
    public void getSuggest(){
        Map<String, String> params = new LinkedHashMap<>();
        params.put("_need_webp", "0");
        params.put("_sig", "6wnUmM%2B%2BeEl/NK3kRCzrDh5DzqI%3D");
        //params.put("_ts", "1572790171");
        params.put("apikey", "0ab215a8b1977939201640fa14c66bab");
        params.put("douban_udid", "17ce66b5b7d85c4cd380c4a38982465423a825a8");
        params.put("dumpling", "290CD640-851D-42FE-9616-0E9100873B0E");
        params.put("loc_id", "108288");
        params.put("sugar", "46001");
        params.put("udid", "b0b995fef0fb1aa0f96defe45393202f96056959");
        params.put("watermelon", "9EDAAEFA-CA6F-49E5-BA4B-99EBE481BB4D");

        // 推荐
        // String url = "https://frodo.douban.com/api/v2/book/suggestion?count=10&&new_struct=1&start=0&with_review=1";
        // app首页模块数据
        String url = "https://frodo.douban.com/api/v2/book/modules";

        //String url = "https://frodo.douban.com/api/v2/book/landing";
        url = url + "?" + DoubanUtils.parseParams(params);
        //发送Post数据并返回数据
        try{
            String data = DoubanUtils.downloadPage(url, false);
            System.out.println(JSON.toJSONString(data));
        }catch (Exception e) {
            e.printStackTrace();
        }

    }

    //@Async("myExecutor")
    //@Scheduled(fixedRate = 60000*60)
    public void updateBookIds(){
        try{
            List<Long> ids = reviewService.findExistsReviewIds();
            if(ids.size() > 0)
                DbBookUtil.setBookIds(ids);
        }catch (Exception e) {
            e.printStackTrace();
        }
    }
}
